
/*
// Save some typing while maintaining type flexibility
#define GAME_TYPES_TEMPLATE template<class Scalar=float, class Vector=Vector3D, \
									 class String=std::string, \
									 template<class T> class Ptr=std::auto_ptr<T> >
*/

#ifndef _MYGAME_HPP
#define _MYGAME_HPP

#include "Engine.hpp"

#include "OpenGL.hpp"

class Ball
{
	Vector m_pos, m_vel, m_force;
	Scalar m_mass;
	Scalar m_radius;
public:
	Ball() : m_pos(0), m_vel(0), m_force(0),
			 m_mass(1.f), m_radius(0.05f) {}
	Ball(Vector pos) : m_pos(pos), m_vel(0),
					   m_force(0), m_mass(1.f),
					   m_radius(0.05f) {}
	Ball(Vector pos,
		 Vector vel) : m_pos(pos), m_vel(vel),
					   m_force(0), m_mass(1.f),
					   m_radius(0.05f) {}
	void update() {
		//Leapfrog integration scheme
		Vector accel = m_force / m_mass /* * timestep */;
		m_vel   += accel;
		m_pos   += /*timestep * */ m_vel;
		m_vel   += 0.5 * accel;
		m_force = 0;
	}
	
	void interact() {
		// TODO: This is a hack to interact with the world borders
		if( m_pos[0] < -1.0) {
			m_pos[0] = -1.0;
			m_vel[0] = -m_vel[0];
		}
		else if( m_pos[0] > 1.0 ) {
			m_pos[0] = 1.0;
			m_vel[0] = -m_vel[0];
		}
		if( m_pos[1] < -1.0) {
			m_pos[1] = -1.0;
			m_vel[1] = -m_vel[1];
		}
		else if( m_pos[1] > 1.0 ) {
			m_pos[1] = 1.0;
			m_vel[1] = -m_vel[1];
		}
	}
	
	void draw() {
		// Draw a plain square
		glPushMatrix();
		glTranslatef(m_pos[0], m_pos[1], 0.f);
		glScalef(m_radius, m_radius, 1.f);
		glColor4f(1.f, 1.f, 1.f, 1.f);
		glBegin(GL_QUADS);
		glVertex2f(-0.5, -0.5);
		glVertex2f(-0.5, 0.5);
		glVertex2f(0.5, 0.5);
		glVertex2f(0.5, -0.5);
		glEnd();
		glPopMatrix();
	}
};

class MyGame : public IInputHandler, public ITickHandler,
			   //public INetworkHandler, public IWorldHandler,
			   public IRendererHandler
{
	Engine* m_engine;
	
	typedef std::vector<Ball> BallVector;
	typedef BallVector::iterator BallIterator;
	
	// Game entities
	BallVector m_balls;
	
public:
	MyGame(Engine* engine);
	
	// Event callbacks called as ITimerHandler
	void onTick();
	
	// Event callbacks called as IInputHandler
	void onKeyDown(IInput* caller, Key key)
	{
		switch( key ) {
		case GK_ESCAPE:
			m_engine->stop();
			break;
		case GK_F4:
			std::cout << "Moment rate: " << m_engine->getTimeKeeper()->getMomentRate() << std::endl;
			std::cout << "Tick rate: " << m_engine->getTimeKeeper()->getTickRate() << std::endl;
			break;
		default:
			break;
		}
	}
	void onKeyUp(IInput* caller, Key key)   {}
	void onMouseDown(IInput* caller, Vector pos, Button button) {}
	void onMouseUp(IInput* caller, Vector pos, Button button) {}
	void onMouseMove(IInput* caller, Vector pos, Button button) {}
	void onQuit(IInput* caller)
	{
		m_engine->stop();
	}
	
    // Event callbacks called as IRendererHandler
	void onFrame(IRenderer* caller);
	
	// Other event callbacks ...
};

#endif //_MYGAME_HPP
